----Typing Is A Ball, Charlie Brown----
A 4am crack                  2015-12-18
-------------------. updated 2015-12-21
                   |___________________

Name: Typing Is A Ball, Charlie Brown
Genre: educational
Year: 1985
Publisher: the disk label and printed
  material say "American School
  Publishing," but the in-game graphics
  say "Random House" (Perhaps a quickie
  rerelease with different copy
  protection? Business baffles me.)
Media: double-sided 5.25-inch floppy
OS: DOS 3.3
Previous cracks: none
Identical cracks:
  #531 Graph Maker
  #530 Make A Face
  #296 Creation
  #198 Working Together
  #197 American History Adventure
  #195 Practical Grammar

Both side are bootable and appear to be
independent. I'll start with side A.

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  immediate disk read error

Locksmith Fast Disk Backup
  unable to read any track

EDD 4 bit copy (no sync, no count)
  no errors, but copy grinds on boot

Copy ][+ nibble editor
  T00 --> standard prologues
  T01+ --> modified address prologue
    ("AB BF D5")
  also modified address epilogue (not
    sure what exactly, not consistent?)

Disk Fixer
  ["O" -> "Input/Output Control"]
  set Address Prologue to "AB BF D5"
  turn off epilogue checking
  T00 looks like a DOS 3.3 RWTS
  T11 looks like a DOS 3.3 disk catalog
  T01,S09 -> startup program is "HELLO"

Why didn't COPYA work?
  modified prologue and epilogue

Why didn't Locksmith FDB work?
  modified prologue and epilogue

Why didn't my EDD copy work?
  I don't know. Maybe a nibble check
  during boot?

Next steps:

  1. capture RWTS with AUTOTRACE
  2. convert disk to standard format
     with Advanced Demuffin
  3. patch RWTS to read demuffin'd disk
  4. find nibble check and bypass it

                   ~

               Chapter 1
In Which We Attempt To Use The Original
    Disk As A Weapon Against Itself


[S6,D1=original disk]
[S6,D2=blank disk]
[S5,D1=my work disk]

]PR#5
CAPTURING BOOT0
...reboots slot 6...
...reboots slot 5...
SAVING BOOT0
/!\ BOOT0 JUMPS TO $08F0
CAPTURING BOOT1
...reboots slot 6...
...reboots slot 5...
SAVING BOOT1
SAVING RWTS

Let's start by seeing what's at $08F0.

]BLOAD BOOT0,A$800
]CALL -151

*8F0L

08F0-   A9 AA       LDA   #$AA
08F2-   85 31       STA   $31     <-- ?
08F4-   A9 00       LDA   #$00
08F6-   8D F1 B6    STA   $B6F1
08F9-   4C 00 BB    JMP   $BB00   <-- !

I've seen this before. The RWTS uses
zero page $31 to check some byte of the
prologue or epilogue. In this case,
probably the data epilogue, since the
address prologue and epilogue are non-
standard.

Then it jumps to $BB00 (from $08F9),
which is probably a nibble check.

]BLOAD BOOT1,A$2600
]CALL -151

*FE89G FE93G     ; disconnect DOS
*B600<2600.2FFFM ; move RWTS into place

*BB00L

BB00-   A9 59       LDA   #$59
BB02-   8D F2 03    STA   $03F2
BB05-   A9 B7       LDA   #$B7
BB07-   EA          NOP
BB08-   8D F3 03    STA   $03F3
BB0B-   49 A5       EOR   #$A5
BB0D-   8D F4 03    STA   $03F4
BB10-   4C 00 B7    JMP   $B700

Hmm, not a nibble check. Just setting
the reset vector.

Now look at this code to match the
data epilogue:

*B92FL

B92F-   BD 8C C0    LDA   $C08C,X
B932-   10 FB       BPL   $B92F
B934-   C9 DE       CMP   #$DE
B936-   D0 0A       BNE   $B942
B938-   EA          NOP
B939-   BD 8C C0    LDA   $C08C,X
B93C-   10 FB       BPL   $B939
B93E-   C5 31       CMP   $31     <-- !
B940-   F0 5C       BEQ   $B99E
B942-   38          SEC
B943-   60          RTS

There's zero page $31, initialized at
$08F0 during boot.

Solution: an IOB module that Advanced
Demuffin calls before calling the
original disk's RWTS. (Read the docs on
my work disk.)

*C500G
...
]CALL -151
]BLOAD ADVANCED DEMUFFIN 1.5

; standard Advanced Demuffin setup
; (unchanged)
1400-   4A          LSR
1401-   8D 22 0F    STA   $0F22
1404-   8C 23 0F    STY   $0F23
1407-   8E 27 0F    STX   $0F27
140A-   A9 01       LDA   #$01
140C-   8D 20 0F    STA   $0F20
140F-   8D 2A 0F    STA   $0F2A

; initialize zero page
1412-   A9 AA       LDA   #$AA
1414-   85 31       STA   $31

; call RWTS
1416-   A9 0F       LDA   #$0F
1418-   A0 1E       LDY   #$1E
141A-   4C 00 BD    JMP   $BD00

*BSAVE IOB $31,A$1400,L$FB

*BRUN ADVANCED DEMUFFIN 1.5

["5" to switch to slot 5]

["R" to load a new RWTS module]
  --> At $B8, load "RWTS" from drive 1

[press "I" to load a new IOB module]
  --> load "IOB $31" from drive 1

["6" to switch to slot 6]

["C" to convert disk]

                 --v--

ADVANCED DEMUFFIN 1.5    (C) 1983, 2014
ORIGINAL BY THE STACK    UPDATES BY 4AM
=======PRESS ANY KEY TO CONTINUE=======
TRK:...................................
+.5:
    0123456789ABCDEF0123456789ABCDEF012
SC0:...................................
SC1:...................................
SC2:...................................
SC3:...................................
SC4:...................................
SC5:...................................
SC6:...................................
SC7:...................................
SC8:...................................
SC9:...................................
SCA:...................................
SCB:...................................
SCC:...................................
SCD:...................................
SCE:...................................
SCF:...................................
=======================================
16SC $00,$00-$22,$0F BY1.0 S6,D1->S6,D2

                 --^--

]PR#5
]CATALOG,S6,D2

C1983 DSR^C#254
102 FREE

 A 002 HELLO
 B 009 CONDENSED
 B 003 JCL.CB.OBJ
 B 002 KBOARD.OBJ
 A 002 START
 B 014 FS.JCL
 B 029 BL.JCL
 B 014 RT.JCL
 A 005 INTRO
 B 004 DIRP
 A 017 IABOWL.OPT
 B 003 ML1
 B 002 W2
 B 003 W3
 B 005 W4
 B 005 W5
 B 005 W6
 B 005 W7
 B 005 W8
 B 005 W9
 B 005 W10
 B 002 RW2
 B 002 RW3
 B 002 RW4
 B 002 RW5
 B 002 RW6
 B 002 RW7
 B 002 RW8
 B 002 RW9
 B 002 RW10
 A 015 IBOWL.OPT
 B 008 BB.JCL
 B 002 OPTS
 A 000 MENU.OPT
 B 011 CC.JCL
 A 014 CCPROG
 B 043 BT.JCL
 A 013 IABSKT.OPT
 B 003 ML2
 B 046 BSK.JCL
 B 046 SHOT.JCL
 B 003 ML3
 B 003 TVL.JCL
 A 002 IQ
 B 003 BE.JCL
 B 002 MSC1

[S6,D1=demuffin'd copy]

]PR#6
...works...

Wait, what?

                   ~

               Chapter 2
  In Which We Angrily Investigate Why
    We Suddenly Have A Working Copy


[S6,D1=mysteriously working copy]
[S5,D1=my work disk]

]BLOAD RWTS,A$2800
]CALL -151
*FE89G FE93G
*B800<2800.2FFFM
*B944L

; routine to find address prologue
B944-   A0 FC       LDY   #$FC
B946-   84 26       STY   $26
B948-   C8          INY
B949-   D0 04       BNE   $B94F
B94B-   E6 26       INC   $26
B94D-   F0 F3       BEQ   $B942

; find prologue nibble #1
B94F-   BD 8C C0    LDA   $C08C,X
B952-   10 FB       BPL   $B94F
B954-   C9 D5       CMP   #$D5    <-- ?
B956-   D0 F0       BNE   $B948
B958-   EA          NOP

I could have sworn the original disk's
address prologue was "AB BF D5".

; and again?
B959-   BD 8C C0    LDA   $C08C,X

; Wait, no BPL loop here! It only reads
; the data latch once.
B95C-   C9 D5       CMP   #$D5

; if data latch is (still) $D5, jump
; right to address field logic
B95E-   F0 12       BEQ   $B972

; otherwise continue and... look for
; the (standard) prologue nibble #2
B960-   BD 8C C0    LDA   $C08C,X
B963-   10 FB       BPL   $B960
B965-   C9 AA       CMP   #$AA
B967-   D0 DF       BNE   $B948

; and the standard prologue nibble #3
B969-   BD 8C C0    LDA   $C08C,X
B96C-   10 FB       BPL   $B969
B96E-   C9 96       CMP   #$96
B970-   D0 D6       BNE   $B948

; decode address field (standard)
B972-   A0 03       LDY   #$03
B974-   A9 00       LDA   #$00
B976-   85 27       STA   $27
B978-   BD 8C C0    LDA   $C08C,X
B97B-   10 FB       BPL   $B978
B97D-   2A          ROL
B97E-   85 26       STA   $26
B980-   BD 8C C0    LDA   $C08C,X
B983-   10 FB       BPL   $B980
B985-   25 26       AND   $26
B987-   99 2C 00    STA   $002C,Y
B98A-   45 27       EOR   $27
B98C-   88          DEY
B98D-   10 E7       BPL   $B976
B98F-   A8          TAY
B990-   D0 02       BNE   $B994

; immediately exit -- no epilogue
; checking at all
B992-   18          CLC
B993-   60          RTS
B994-   38          SEC
B995-   60          RTS
B996-   00          BRK   | These are
B997-   00          BRK   | really on
B998-   00          BRK   | the disk,
B999-   00          BRK   | just taking
B99A-   00          BRK   | up space,
B99B-   00          BRK   | much like
B99C-   00          BRK   | this
B99D-   00          BRK   | comment.
B99E-   18          CLC
B99F-   60          RTS

This RWTS will accept two different
address prologues. If it finds a $D5
followed by a timing bit, that's it;
that's the entire address prologue.
Without the timing bit, it looks for
the rest of a standard prologue.

Turning back to the Copy II Plus nibble
editor, I see the crucial detail that I
missed the first time. The "D5" that I
thought was the third nibble in the
address prologue is actually the first,
and it is displayed in inverse, meaning
it has timing bits after it. (Sorry
that doesn't show up in text.)

The disk does happen to have a 3-nibble
address prologue on every sector, but
it only uses the one of them (plus a
timing bit). I'm guessing that this
accidental consistency is a side effect
of the original mastering process.

Why didn't the EDD copy work?
  EDD preserved the original address
  prologue but not the timing bits.
  The prologue checker finds the $D5
  (at $B954) but no timing bit after it
  (at $B95C), so the disk can't read
  itself. There was never any separate
  nibble check; the structure of the
  disk itself is designed to foil
  nibble copiers.

Why did the demuffin'd copy work?
  Advanced Demuffin wrote out the data
  from each sector onto a standard disk
  that uses "D5 AA 96" prologue and "DE
  AA EB" epilogue. The RWTS finds the
  first $D5, doesn't find a timing bit,
  but it finds the remaining standard
  prologue (AA 96) and decides that it
  found a valid address field. Thus, no
  RWTS patches are necessary.

Side B has identical protection.

Quod erat liberandum.

                   ~

               Chapter 3
  In Which We Patch The RWTS Anyway,
            And Explain Why


Emulators aren't perfect. Real hardware
is complicated, and the Disk II is
especially difficult to emulate (being,
as it is, an analog device). Many edge
cases are left as "an exercise for the
reader." Many copy protection schemes
rely on edge cases to work.

You may see where this is going.

My crack of this disk works perfectly
on real hardware. It also works in most
Apple II emulators that run on modern
hardware. But it does not work in every
emulator, so I set out to discover why.

Here is the RWTS code from the original
disk, which I have left untouched thus
far:

; find address prologue #1
B94F-   BD 8C C0    LDA   $C08C,X
B952-   10 FB       BPL   $B94F
B954-   C9 D5       CMP   #$D5
B956-   D0 F0       BNE   $B948

; kill 2 CPU cycles
B958-   EA          NOP

; read data latch one more time
B959-   BD 8C C0    LDA   $C08C,X

; if the data latch still has $D5 in it
; then we are reading an original disk
; which uses a single nibble + timing
; bit as the address prologue, so jump
; forward to start parsing the address
; field
B95C-   C9 D5       CMP   #$D5
B95E-   F0 12       BEQ   $B972

; otherwise we are reading a standard
; disk (like a data disk -- or, in my
; case, a cracked copy), so continue
; checking the prologue for the regular
; second and third nibbles
B960-   BD 8C C0    LDA   $C08C,X
B963-   10 FB       BPL   $B960
B965-   C9 AA       CMP   #$AA
B967-   D0 DF       BNE   $B948
B969-   BD 8C C0    LDA   $C08C,X
B96C-   10 FB       BPL   $B969
B96E-   C9 96       CMP   #$96
B970-   D0 D6       BNE   $B948

At $B95C, we're checking the data latch
to see if it is still holding the $D5
value. On real Disk II hardware, this
will only be true if there was an extra
timing bit after the $D5. The timing
bit causes the data latch to retain its
value for 4 more CPU cycles. This is
the crux of the entire copy protection.

Here's the problem: some emulators will
(incorrectly) retain the $D5 value in
the data latch for longer than a real
drive would. This makes the RWTS think
that it's reading an original disk.
Specifically, $B95E (incorrectly)
branches to $B972 and tries to start
parsing the address field. Of course,
on my crack, the address field hasn't
started yet -- there are still two more
nibbles in the address prologue. The
address field checksum fails because
we're off by two nibbles, disks grind,
programs crash, everything is terrible.

The solution is tricky, because we're
in the middle of RWTS code so timing is
tight (even in misbehaving emulators).
But if we change the code at $B958 to
branch to $B960, we'll have enough time
to catch the second and third nibbles
of the standard address prologue. This
should work on real hardware, faithful
emulators, and misbehaving emulators
(since we'll never execute the compare
at $B95C that went awry).

The patched RWTS code:

B94F-   BD 8C C0    LDA   $C08C,X
B952-   10 FB       BPL   $B94F
B954-   C9 D5       CMP   #$D5
B956-   D0 F0       BNE   $B948
B958-   F0 06       BEQ   $B960 ------+
B95A-  [8C C0] \                      |
B95C-  [C9 D5]  } never executed      |
B95E-  [F0 12] /                      |
B960-   BD 8C C0    LDA   $C08C,X <---+
B963-   10 FB       BPL   $B960
B965-   C9 AA       CMP   #$AA
B967-   D0 DF       BNE   $B948

T00,S03,$58 change "EA BD" to "F0 06"

                   ~

               Epilogue
           Beyond The Crack


Side A of the original disk had somehow
corrupted its options file, which
caused the program to crash in a
seemingly innocuous string manipulation
subroutine. As a paranoid cracker who
assumes that all innocuous crashes are
intentionally malicious, this took a
while for me to debug. (Checking the
original disk did not occur to me.) I
fixed it by running through the in-game
options screen, which re-saved the file
with proper values.

                   ~

               Changelog


2015-12-21

- apply and explain patch for legacy
  emulators

---------------------------------------
A 4am crack                     No. 532
------------------EOF------------------
